Objectives

  • Identify common structures and features of interactivity
  • Review several examples of interactive visualizations
  • Introduce htmlwidgets, plotly, and highcharter for generating interactive graphics in R
library(tidyverse)
library(knitr)
library(broom)
library(stringr)
library(modelr)
library(forcats)
library(haven)
library(plotly)

options(digits = 3)
set.seed(1234)
theme_set(theme_minimal())

Structuring interactivity

Visual information-seeking mantra

Overview first, zom and filter, then details on demand

This mantra first coined by Ben Schneiderman (a professor of computer science) can be seen as a succinct summary of the purpose of data visualization:

  1. Present the most important figures or most relevant points to the audience
  2. Allow readers to dig into the information, explore, and come up with their own stories

Interactivity enhances our ability to accomplish the second point by presenting a structured way for readers to interact and explore the data, without having to know research design, computer programming, or other substantial technical skills that are a hurdle for the average reader. There are several design guidelines we can keep in mind as we design interactive graphics to keep them orderly and useful (rather than introducing interactivity that is pointless, confusing, or misleading).

Linear vs non-linear

Some visualizations will be linear - each step of the presentation depends on understanding the previous one. Others will be non-linear, giving the reader a choice in navigation and the direction of the story.

Think choose your own adventure stories.

Think “choose your own adventure” stories.

Both approaches should utilize an introduction to setup the question and topic, but diverge quickly in the possible options the reader can explore.

Interaction techniques

  • Scroll and pan
  • Zoom
  • Open and close
  • Sort and rearrange
  • Search and filter

Examples of interactive graphics

Central limit theorem

Central Limit Theorem Visualized in D3

  • Interactive animation designed to teach the central limit theorem
  • Every time the ball his a triangle it has a 50/50 chance of going to the left or right (i.e. a coin flip)
  • As the animation plays out, the balls are sorted into bins which start to form a normal distribution
  • Very linear format - user controls very little of the animation
    • Can adjust the delay - rate at which balls fall
    • Bins - number of bins into which the balls can fall

Seeing theory

Seeing Theory: A visual introduction to probability and statistics

  • Makes heavy use of a linear format to teach basic statistical principles
  • Lots of animations
  • Pan and scroll down the page to the next demonstration module
  • Open and close
    • Open definitions of different estimation terms (bias, variance, mean squared error)

The changing American diet

The Changing American Diet

  • Very linear structure
  • Animation used to identify change over time by shifting foods up and down based on relative frequency
  • Direct controls for user
    • Speed
    • Scale
  • Still situated within an article setting up the question and explaining the results - graphic does not stand alone (but it could)

How (un)popular is Donald Trump?

How popular/unpopular is Donald Trump?

  • More of a standalone graphic
  • Linear (but also non-linear) structure
  • Open/close to see all the individual data points used to generate the trendline
  • Open/close to see exact data point values
  • Zoom in and out on different time periods

Gun deaths in America

Gun Deaths in America

  • Highly linearized storyline
  • Animation goes from description to description
  • Ends with an interaction where users can search and filter by different variables
  • What is the benefit to making this interactive?

You draw it

You Draw It: Just How Bad Is the Drug Overdose Epidemic?

  • Linear structure
  • Allows users to “fill in” the missing years, rather than just presenting the answer
  • How does interactivity enhance this visualization?
    • Allows users to explicitly confront misperceptions they have about major causes of death in the United States
  • Uses open and close windows to present details about deaths at the county-level on a cartogram

Movie explorer

Movie explorer

  • Example of shiny app
  • Non-linear structure - user has complete freedom to change the inputs
  • Can change variables on the graph’s axes
  • Hover over data points on graph to get more details
  • Can expand the size of the graph
  • Better situated with an accompanying article/post describing the data and perhaps highlighting some noteworthy trends

Revenue effect of restoring the tax-preferred status

Revenue Effect of Restoring the Tax-Preferred Status of Over-the-Counter Drugs Purchased Through Health Savings Accounts, Flexible Spending Accounts, and Health Reimbusement Arrangements through the Repeal of Section 9003 of the Affordable Care Act.

  • Widget designed for think tank in conjunction with policy report on a tax reform bill
  • Changing inputs creates a new “user model” projecting the estimated revenue effect of the tax policy given varying assumptions about the state of the world
  • As inputs change, graph is redrawn and table is updated
  • Hovering over data points on the graph identifies the annual expected revenue effect for each model, rather than pasting it in as a table
  • Clicking on the legend hides/reveals different models
  • Built using shiny, ggplot2, plotly, and Excel(!)

America’s public bible

America’s Public Bible: Biblical Quotations in U.S. Newspapers

  • Digital humanities project
  • Combines linear and non-linear structure
  • On front page, open and close used to provide exact values for data points
  • Exploration
    • Embeds a Shiny application for examining use over time of different bible verses
    • Search and filter
    • Pan and zoom

Interactive graphics in R

ggplot2 does not have built-in interactivity. The successor to ggplot2, ggvis, is still in development and not ready for production-level graphics.

However we can still build interactive graphics within the R environment. This is accomplished by a series of packages that generate JavaScript visualizations directly within R. JavaScript is a core technology within the World Wide Web framework, and is used to render websites. The majority of the demonstration visualizations above were created using JavaScript.

To build these types of graphs, we could shift entirely to an interactive graphics library based on Javascript, such as D3, and write all of our code in that format. The drawbacks to this approach are:

  • Learning another programming language is time-consuming
  • D3 visualizations are typically meant for presenting visualizations in their final form, not quickly rendering exploratory graphs, so there is a lot of unnecessary code-writing involved.
    • Think about how ggplot() makes many default assumptions when you write code to generate a graph. Normally the defaults work correctly, but you can always override them if necessary. With D3 and other JavaScript libraries, you cannot rely on these defaults.

htmlwidgets

htmlwidgets is a framework for creating R bindings to JavaScript libraries. In essence, packages built on this framework take the R code that you write, process it, and convert it to the appropriate JavaScript code. From here, you can view the resulting graph in RStudio like an ordinary plot, embed it within an R Markdown document, or save it as a standalone .html page to share with others or post online.

Some of the packages we will explore this week are built using htmlwidgets; others use their own approach to bind R functions onto JavaScript libraries.

plotly

Plotly is an online analytics and data visualization tool built using Python, JavaScript, and D3. They offer a commercial product for designing graphics via a point-and-click interface online, but have developed open-source packages for generating plotly graphs (plotly.js), as well as API libraries for generating plotly graphs in R.

ggplotly()

ggplot2 can be readily converted into interactive graphics in plotly through the use of ggplotly():

library(plotly)

# basic scatterplot
p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point()

ggplotly(p)
# add color
p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point(aes(color = class))

ggplotly(p)
# add smoothing line
ggplotly(p +
           geom_smooth())
# add vehicle labels to tooltips
p <- ggplot(mpg, aes(displ, hwy)) +
  geom_point(aes(color = class, text = str_c(manufacturer, model, sep = " "))) +
  geom_smooth()

ggplotly(p)
# dahl bubbleplot
dahl <- read_dta("data/LittleDahl.dta")
dahl_mod <-lm(nulls ~ age + tenure + unified, data = dahl)

dahl_augment <- dahl %>%
  mutate(hat = hatvalues(dahl_mod),
         student = rstudent(dahl_mod),
         cooksd = cooks.distance(dahl_mod))

# use size
p <- ggplot(dahl_augment, aes(hat, student)) +
  geom_hline(yintercept = 0, linetype = 2) +
  geom_point(aes(size = cooksd), shape = 1) +
  geom_text(data = dahl_augment %>%
              arrange(-cooksd) %>%
              slice(1:10),
            aes(label = Congress)) +
  scale_size_continuous(range = c(1, 20)) +
  labs(x = "Leverage",
       y = "Studentized residual") +
  theme(legend.position = "none")

ggplotly(p)

Modifying ggplotly() objects

str(plotly_build(p))
## List of 8
##  $ x            :List of 9
##   ..$ data     :List of 3
##   .. ..$ :List of 12
##   .. .. ..$ x         : num [1:2] 0.00661 0.11829
##   .. .. ..$ y         : num [1:2] 0 0
##   .. .. ..$ text      : chr "yintercept: 0"
##   .. .. ..$ type      : chr "scatter"
##   .. .. ..$ mode      : chr "lines"
##   .. .. ..$ line      :List of 3
##   .. .. .. ..$ width: num 1.89
##   .. .. .. ..$ color: chr "rgba(0,0,0,1)"
##   .. .. .. ..$ dash : chr "dash"
##   .. .. ..$ hoveron   : chr "points"
##   .. .. ..$ showlegend: logi FALSE
##   .. .. ..$ xaxis     : chr "x"
##   .. .. ..$ yaxis     : chr "y"
##   .. .. ..$ hoverinfo : chr "text"
##   .. .. ..$ frame     : chr NA
##   .. ..$ :List of 12
##   .. .. ..$ x         : num [1:104] 0.0974 0.0664 0.1132 0.0524 0.0563 ...
##   .. .. ..$ y         : num [1:104] 0.3301 -0.0277 0.5113 -0.0148 0.1631 ...
##   .. .. ..$ text      : chr [1:104] "cooksd: 2.96e-03<br />hat: 0.0974<br />student:  0.33012" "cooksd: 1.38e-05<br />hat: 0.0664<br />student: -0.02775" "cooksd: 8.41e-03<br />hat: 0.1132<br />student:  0.51131" "cooksd: 3.07e-06<br />hat: 0.0524<br />student: -0.01482" ...
##   .. .. ..$ type      : chr "scatter"
##   .. .. ..$ mode      : chr "markers"
##   .. .. ..$ marker    :List of 6
##   .. .. .. ..$ autocolorscale: logi FALSE
##   .. .. .. ..$ color         : chr "rgba(0,0,0,1)"
##   .. .. .. ..$ opacity       : num 1
##   .. .. .. ..$ size          : num [1:104] 12.06 4.34 17.72 4.03 6.82 ...
##   .. .. .. ..$ symbol        : chr "circle-open"
##   .. .. .. ..$ line          :List of 2
##   .. .. .. .. ..$ width: num 1.89
##   .. .. .. .. ..$ color: chr "rgba(0,0,0,1)"
##   .. .. ..$ hoveron   : chr "points"
##   .. .. ..$ showlegend: logi FALSE
##   .. .. ..$ xaxis     : chr "x"
##   .. .. ..$ yaxis     : chr "y"
##   .. .. ..$ hoverinfo : chr "text"
##   .. .. ..$ frame     : chr NA
##   .. ..$ :List of 12
##   .. .. ..$ x         : num [1:10] 0.0514 0.073 0.0208 0.0361 0.102 ...
##   .. .. ..$ y         : num [1:10] 4.42 3.02 4.48 2.14 -1.07 ...
##   .. .. ..$ text      : chr [1:10] "74th" "98th" "104th" "67th" ...
##   .. .. ..$ textfont  :List of 2
##   .. .. .. ..$ size : num 14.7
##   .. .. .. ..$ color: chr "rgba(0,0,0,1)"
##   .. .. ..$ type      : chr "scatter"
##   .. .. ..$ mode      : chr "text"
##   .. .. ..$ hoveron   : chr "points"
##   .. .. ..$ showlegend: logi FALSE
##   .. .. ..$ xaxis     : chr "x"
##   .. .. ..$ yaxis     : chr "y"
##   .. .. ..$ hoverinfo : chr "text"
##   .. .. ..$ frame     : chr NA
##   ..$ layout   :List of 8
##   .. ..$ margin    :List of 4
##   .. .. ..$ t: num 26.2
##   .. .. ..$ r: num 7.31
##   .. .. ..$ b: num 40.2
##   .. .. ..$ l: num 31.4
##   .. ..$ font      :List of 3
##   .. .. ..$ color : chr "rgba(0,0,0,1)"
##   .. .. ..$ family: chr ""
##   .. .. ..$ size  : num 14.6
##   .. ..$ xaxis     :List of 25
##   .. .. ..$ domain        : num [1:2] 0 1
##   .. .. ..$ type          : chr "linear"
##   .. .. ..$ autorange     : logi FALSE
##   .. .. ..$ tickmode      : chr "array"
##   .. .. ..$ range         : num [1:2] 0.00661 0.11829
##   .. .. ..$ ticktext      : chr [1:3] "0.03" "0.06" "0.09"
##   .. .. ..$ tickvals      : num [1:3] 0.03 0.06 0.09
##   .. .. ..$ ticks         : chr ""
##   .. .. ..$ tickcolor     : logi NA
##   .. .. ..$ ticklen       : num 3.65
##   .. .. ..$ tickwidth     : num 0
##   .. .. ..$ showticklabels: logi TRUE
##   .. .. ..$ tickfont      :List of 3
##   .. .. .. ..$ color : chr "rgba(77,77,77,1)"
##   .. .. .. ..$ family: chr ""
##   .. .. .. ..$ size  : num 11.7
##   .. .. ..$ tickangle     : num 0
##   .. .. ..$ showline      : logi FALSE
##   .. .. ..$ linecolor     : logi NA
##   .. .. ..$ linewidth     : num 0
##   .. .. ..$ showgrid      : logi TRUE
##   .. .. ..$ gridcolor     : chr "rgba(235,235,235,1)"
##   .. .. ..$ gridwidth     : num 0.664
##   .. .. ..$ zeroline      : logi FALSE
##   .. .. ..$ anchor        : chr "y"
##   .. .. ..$ title         : chr "Leverage"
##   .. .. ..$ titlefont     :List of 3
##   .. .. .. ..$ color : chr "rgba(0,0,0,1)"
##   .. .. .. ..$ family: chr ""
##   .. .. .. ..$ size  : num 14.6
##   .. .. ..$ hoverformat   : chr ".2f"
##   .. ..$ yaxis     :List of 25
##   .. .. ..$ domain        : num [1:2] 0 1
##   .. .. ..$ type          : chr "linear"
##   .. .. ..$ autorange     : logi FALSE
##   .. .. ..$ tickmode      : chr "array"
##   .. .. ..$ range         : num [1:2] -1.98 4.79
##   .. .. ..$ ticktext      : chr [1:3] "0" "2" "4"
##   .. .. ..$ tickvals      : num [1:3] 0 2 4
##   .. .. ..$ ticks         : chr ""
##   .. .. ..$ tickcolor     : logi NA
##   .. .. ..$ ticklen       : num 3.65
##   .. .. ..$ tickwidth     : num 0
##   .. .. ..$ showticklabels: logi TRUE
##   .. .. ..$ tickfont      :List of 3
##   .. .. .. ..$ color : chr "rgba(77,77,77,1)"
##   .. .. .. ..$ family: chr ""
##   .. .. .. ..$ size  : num 11.7
##   .. .. ..$ tickangle     : num 0
##   .. .. ..$ showline      : logi FALSE
##   .. .. ..$ linecolor     : logi NA
##   .. .. ..$ linewidth     : num 0
##   .. .. ..$ showgrid      : logi TRUE
##   .. .. ..$ gridcolor     : chr "rgba(235,235,235,1)"
##   .. .. ..$ gridwidth     : num 0.664
##   .. .. ..$ zeroline      : logi FALSE
##   .. .. ..$ anchor        : chr "x"
##   .. .. ..$ title         : chr "Studentized residual"
##   .. .. ..$ titlefont     :List of 3
##   .. .. .. ..$ color : chr "rgba(0,0,0,1)"
##   .. .. .. ..$ family: chr ""
##   .. .. .. ..$ size  : num 14.6
##   .. .. ..$ hoverformat   : chr ".2f"
##   .. ..$ shapes    :List of 1
##   .. .. ..$ :List of 9
##   .. .. .. ..$ type     : chr "rect"
##   .. .. .. ..$ fillcolor: logi NA
##   .. .. .. ..$ line     :List of 3
##   .. .. .. .. ..$ color   : logi NA
##   .. .. .. .. ..$ width   : num 0
##   .. .. .. .. ..$ linetype: chr(0) 
##   .. .. .. ..$ yref     : chr "paper"
##   .. .. .. ..$ xref     : chr "paper"
##   .. .. .. ..$ x0       : num 0
##   .. .. .. ..$ x1       : num 1
##   .. .. .. ..$ y0       : num 0
##   .. .. .. ..$ y1       : num 1
##   .. ..$ showlegend: logi FALSE
##   .. ..$ legend    :List of 4
##   .. .. ..$ bgcolor    : logi NA
##   .. .. ..$ bordercolor: logi NA
##   .. .. ..$ borderwidth: num 0
##   .. .. ..$ font       :List of 3
##   .. .. .. ..$ color : chr "rgba(0,0,0,1)"
##   .. .. .. ..$ family: chr ""
##   .. .. .. ..$ size  : num 11.7
##   .. ..$ hovermode : chr "closest"
##   ..$ source   : chr "A"
##   ..$ attrs    :List of 3
##   .. ..$ 832f7bfcfea3:List of 2
##   .. .. ..$ yintercept:Class 'formula'  language ~yintercept
##   .. .. .. .. ..- attr(*, ".Environment")=<environment: 0x7fdc5819c660> 
##   .. .. ..$ type      : chr "ggplotly"
##   .. .. ..- attr(*, "class")= chr "plotly_eval"
##   .. ..$ 832f1eb1beed:List of 3
##   .. .. ..$ size:Class 'formula'  language ~cooksd
##   .. .. .. .. ..- attr(*, ".Environment")=<environment: 0x7fdc581a5f40> 
##   .. .. ..$ x   :Class 'formula'  language ~hat
##   .. .. .. .. ..- attr(*, ".Environment")=<environment: 0x7fdc581a5f40> 
##   .. .. ..$ y   :Class 'formula'  language ~student
##   .. .. .. .. ..- attr(*, ".Environment")=<environment: 0x7fdc581a5f40> 
##   .. .. ..- attr(*, "class")= chr "plotly_eval"
##   .. ..$ 832f276dc959:List of 3
##   .. .. ..$ label:Class 'formula'  language ~Congress
##   .. .. .. .. ..- attr(*, ".Environment")=<environment: 0x7fdc581cbf40> 
##   .. .. ..$ x    :Class 'formula'  language ~hat
##   .. .. .. .. ..- attr(*, ".Environment")=<environment: 0x7fdc581cbf40> 
##   .. .. ..$ y    :Class 'formula'  language ~student
##   .. .. .. .. ..- attr(*, ".Environment")=<environment: 0x7fdc581cbf40> 
##   .. .. ..- attr(*, "class")= chr "plotly_eval"
##   ..$ cur_data : chr "832f7bfcfea3"
##   ..$ visdat   :List of 3
##   .. ..$ 832f7bfcfea3:function (y)  
##   .. ..$ 832f1eb1beed:function (y)  
##   .. ..$ 832f276dc959:function (y)  
##   ..$ config   :List of 2
##   .. ..$ modeBarButtonsToAdd:List of 1
##   .. .. ..$ :List of 3
##   .. .. .. ..$ name : chr "Collaborate"
##   .. .. .. ..$ icon :List of 4
##   .. .. .. .. ..$ width  : num 1000
##   .. .. .. .. ..$ ascent : num 500
##   .. .. .. .. ..$ descent: num -50
##   .. .. .. .. ..$ path   : chr "M487 375c7-10 9-23 5-36l-79-259c-3-12-11-23-22-31-11-8-22-12-35-12l-263 0c-15 0-29 5-43 15-13 10-23 23-28 37-5 13-5 25-1 37 0 0"| __truncated__
##   .. .. .. ..$ click:Class 'JS_EVAL'  chr "function(gd) { \n        // is this being viewed in RStudio?\n        if (location.search == '?viewer_pane=1') {\n          ale"| __truncated__
##   .. ..$ cloud              : logi FALSE
##   ..$ highlight:List of 6
##   .. ..$ on        : chr "plotly_click"
##   .. ..$ persistent: logi FALSE
##   .. ..$ dynamic   : logi FALSE
##   .. ..$ selectize : logi FALSE
##   .. ..$ opacityDim: num 0.2
##   .. ..$ selected  :List of 1
##   .. .. ..$ opacity: num 1
##   ..$ base_url : chr "https://plot.ly"
##   ..- attr(*, "TOJSON_FUNC")=function (x, ...)  
##  $ width        : NULL
##  $ height       : NULL
##  $ sizingPolicy :List of 6
##   ..$ defaultWidth : chr "100%"
##   ..$ defaultHeight: num 400
##   ..$ padding      : NULL
##   ..$ viewer       :List of 6
##   .. ..$ defaultWidth : NULL
##   .. ..$ defaultHeight: NULL
##   .. ..$ padding      : NULL
##   .. ..$ fill         : logi TRUE
##   .. ..$ suppress     : logi FALSE
##   .. ..$ paneHeight   : NULL
##   ..$ browser      :List of 4
##   .. ..$ defaultWidth : NULL
##   .. ..$ defaultHeight: NULL
##   .. ..$ padding      : NULL
##   .. ..$ fill         : logi TRUE
##   ..$ knitr        :List of 3
##   .. ..$ defaultWidth : NULL
##   .. ..$ defaultHeight: NULL
##   .. ..$ figure       : logi TRUE
##  $ dependencies :List of 3
##   ..$ :List of 10
##   .. ..$ name      : chr "jquery"
##   .. ..$ version   : chr "1.11.3"
##   .. ..$ src       :List of 1
##   .. .. ..$ file: chr "/Library/Frameworks/R.framework/Versions/3.3/Resources/library/crosstalk/lib/jquery"
##   .. ..$ meta      : NULL
##   .. ..$ script    : chr "jquery.min.js"
##   .. ..$ stylesheet: NULL
##   .. ..$ head      : NULL
##   .. ..$ attachment: NULL
##   .. ..$ package   : NULL
##   .. ..$ all_files : logi TRUE
##   .. ..- attr(*, "class")= chr "html_dependency"
##   ..$ :List of 10
##   .. ..$ name      : chr "crosstalk"
##   .. ..$ version   : chr "1.0.0"
##   .. ..$ src       :List of 1
##   .. .. ..$ file: chr "/Library/Frameworks/R.framework/Versions/3.3/Resources/library/crosstalk/www"
##   .. ..$ meta      : NULL
##   .. ..$ script    : chr "js/crosstalk.min.js"
##   .. ..$ stylesheet: chr "css/crosstalk.css"
##   .. ..$ head      : NULL
##   .. ..$ attachment: NULL
##   .. ..$ package   : NULL
##   .. ..$ all_files : logi TRUE
##   .. ..- attr(*, "class")= chr "html_dependency"
##   ..$ :List of 10
##   .. ..$ name      : chr "typedarray"
##   .. ..$ version   : chr "0.1"
##   .. ..$ src       :List of 1
##   .. .. ..$ file: chr "/Library/Frameworks/R.framework/Versions/3.3/Resources/library/plotly/htmlwidgets/lib/typedarray"
##   .. ..$ meta      : NULL
##   .. ..$ script    : chr "typedarray.min.js"
##   .. ..$ stylesheet: NULL
##   .. ..$ head      : NULL
##   .. ..$ attachment: NULL
##   .. ..$ package   : NULL
##   .. ..$ all_files : logi TRUE
##   .. ..- attr(*, "class")= chr "html_dependency"
##  $ elementId    : chr "832f18be0648"
##  $ preRenderHook:function (p, registerFrames = TRUE)  
##  $ jsHooks      :List of 1
##   ..$ render:List of 1
##   .. ..$ :List of 2
##   .. .. ..$ code: chr "function(el, x) { var ctConfig = crosstalk.var('plotlyCrosstalkOpts').set({\"on\":\"plotly_click\",\"persistent\":false,\"dynam"| __truncated__
##   .. .. ..$ data: NULL
##  - attr(*, "class")= chr [1:2] "plotly" "htmlwidget"
##  - attr(*, "package")= chr "plotly"

ggplotly() stores all the components of the graph in a list object in R, which you can directly access using plotly_build(). To modify components of the ggplotly() object, “simply” modify the appropriate element in plotly_build(). Let’s use the OTC tax widget as an example, converting it into a non-Shiny object.1

library(tidyverse)
library(stringr)
library(plotly)
library(rJava)
library(XLConnect)

options(digits = 3)
set.seed(1234)
theme_set(theme_minimal())


# function to convert outputs to tidy data frame
tidy_outputs <- function(outputs){
  outputs %>%
    as_tibble %>%
    gather(year, value, -Revenue.effect, convert = TRUE) %>%
    mutate(year = parse_number(year),
           Revenue.effect = factor(Revenue.effect,
                                   levels = c("User Model",
                                              "The Joint Committee on Taxation",
                                              "The Lindsey Group")))
}

# load model workbook and default inputs and outputs
# sorry i cannot share this file with you - it's proprietary
model <- loadWorkbook("data/OTCModelFeb2017rev5-Widget.xlsx")
model_inputs <- readWorksheet(model, "R-in")

# create color palette for graph
cbbpal <- c('#1b9e77', '#d95f02', '#7570b3')

# generate data
model_data <- tidy_outputs(readWorksheet(model, "R-out"))
model_data

# generate basic graph
g <- model_data %>%
  rename(Year = year, `Revenue effect` = value, `Model` = Revenue.effect) %>%
  ggplot(aes(Year, `Revenue effect`, color = Model)) +
  geom_line(size = 1.5) +
  scale_color_manual(values = cbbpal) +
  guides(color = guide_legend(nrow = 1)) +
  labs(x = "Year",
       y = "Millions (USD)",
       color = NULL) +
  theme_minimal(base_size = 14)

# static version
g

# plotly version
p <- plotly_build(g)
p

# view legend components
p$x$layout$legend

# fix legend position
p$x$layout$legend$x <- .5
p$x$layout$legend$y <- -.3
p$x$layout$legend$xanchor <- "center"
p$x$layout$legend$yanchor <- "top"
p$x$layout$legend$orientation <- "h"

p

# view structure
p$x$data[[1]]

# need to change the $text element - written in html
p$x$data[[1]]$text <- str_replace_all(p$x$data[[1]]$text,
                                      pattern = "`Revenue effect`", "Revenue effect")
p$x$data[[2]]$text <- str_replace_all(p$x$data[[2]]$text,
                                      pattern = "`Revenue effect`", "Revenue effect")
p$x$data[[3]]$text <- str_replace_all(p$x$data[[3]]$text,
                                      pattern = "`Revenue effect`", "Revenue effect")

p

Session Info

devtools::session_info()
##  setting  value                       
##  version  R version 3.3.3 (2017-03-06)
##  system   x86_64, darwin13.4.0        
##  ui       X11                         
##  language (EN)                        
##  collate  en_US.UTF-8                 
##  tz       America/Chicago             
##  date     2017-05-01                  
## 
##  package     * version    date       source                           
##  assertthat    0.2.0      2017-04-11 cran (@0.2.0)                    
##  backports     1.0.5      2017-01-18 CRAN (R 3.3.2)                   
##  broom       * 0.4.2      2017-02-13 CRAN (R 3.3.2)                   
##  colorspace    1.3-2      2016-12-14 CRAN (R 3.3.2)                   
##  DBI           0.6        2017-03-09 CRAN (R 3.3.3)                   
##  devtools      1.12.0     2016-06-24 CRAN (R 3.3.0)                   
##  digest        0.6.12     2017-01-27 CRAN (R 3.3.2)                   
##  dplyr       * 0.5.0      2016-06-24 CRAN (R 3.3.0)                   
##  evaluate      0.10       2016-10-11 CRAN (R 3.3.0)                   
##  forcats     * 0.2.0      2017-01-23 CRAN (R 3.3.2)                   
##  foreign       0.8-67     2016-09-13 CRAN (R 3.3.3)                   
##  ggplot2     * 2.2.1.9000 2017-05-01 Github (hadley/ggplot2@f4398b6)  
##  gtable        0.2.0      2016-02-26 CRAN (R 3.3.0)                   
##  haven       * 1.0.0      2016-09-23 cran (@1.0.0)                    
##  hms           0.3        2016-11-22 CRAN (R 3.3.2)                   
##  htmltools     0.3.6      2017-04-28 cran (@0.3.6)                    
##  htmlwidgets   0.8        2016-11-09 CRAN (R 3.3.1)                   
##  httr          1.2.1      2016-07-03 CRAN (R 3.3.0)                   
##  jsonlite      1.4        2017-04-08 cran (@1.4)                      
##  knitr       * 1.15.1     2016-11-22 cran (@1.15.1)                   
##  lattice       0.20-34    2016-09-06 CRAN (R 3.3.3)                   
##  lazyeval      0.2.0      2016-06-12 CRAN (R 3.3.0)                   
##  lubridate     1.6.0      2016-09-13 CRAN (R 3.3.0)                   
##  magrittr      1.5        2014-11-22 CRAN (R 3.3.0)                   
##  memoise       1.0.0      2016-01-29 CRAN (R 3.3.0)                   
##  mnormt        1.5-5      2016-10-15 CRAN (R 3.3.0)                   
##  modelr      * 0.1.0      2016-08-31 CRAN (R 3.3.0)                   
##  munsell       0.4.3      2016-02-13 CRAN (R 3.3.0)                   
##  nlme          3.1-131    2017-02-06 CRAN (R 3.3.3)                   
##  plotly      * 4.6.0      2017-04-25 CRAN (R 3.3.3)                   
##  plyr          1.8.4      2016-06-08 CRAN (R 3.3.0)                   
##  psych         1.7.3.21   2017-03-22 CRAN (R 3.3.2)                   
##  purrr       * 0.2.2      2016-06-18 CRAN (R 3.3.0)                   
##  R6            2.2.0      2016-10-05 CRAN (R 3.3.0)                   
##  Rcpp          0.12.10    2017-03-19 cran (@0.12.10)                  
##  readr       * 1.1.0      2017-03-22 cran (@1.1.0)                    
##  readxl        0.1.1      2016-03-28 CRAN (R 3.3.0)                   
##  reshape2      1.4.2      2016-10-22 CRAN (R 3.3.0)                   
##  rlang         0.0.0.9018 2017-05-01 Github (hadley/rlang@460323e)    
##  rmarkdown     1.3        2016-12-21 CRAN (R 3.3.2)                   
##  rprojroot     1.2        2017-01-16 CRAN (R 3.3.2)                   
##  rvest         0.3.2      2016-06-17 CRAN (R 3.3.0)                   
##  scales        0.4.1      2016-11-09 CRAN (R 3.3.1)                   
##  stringi       1.1.2      2016-10-01 CRAN (R 3.3.0)                   
##  stringr     * 1.2.0      2017-02-18 CRAN (R 3.3.2)                   
##  tibble      * 1.3.0.9001 2017-05-01 Github (tidyverse/tibble@08af6b0)
##  tidyr       * 0.6.1      2017-01-10 CRAN (R 3.3.2)                   
##  tidyverse   * 1.1.1      2017-01-27 CRAN (R 3.3.2)                   
##  viridisLite   0.2.0      2017-03-24 cran (@0.2.0)                    
##  withr         1.0.2      2016-06-20 CRAN (R 3.3.0)                   
##  xml2          1.1.1      2017-01-24 CRAN (R 3.3.2)                   
##  yaml          2.1.14     2016-11-12 cran (@2.1.14)

  1. In fact this is the exact trouble I went through when building the app. It’s easier to work on the graph portion in a static environment first, before incorporating the Shiny components.